C++模板参数推导的一个容易被忽略的细节 您所在的位置:网站首页 c++ 左值 C++模板参数推导的一个容易被忽略的细节

C++模板参数推导的一个容易被忽略的细节

2023-03-26 06:58| 来源: 网络整理| 查看: 265

在C++17以后,我们使用模板函数和模板类型时,已经可以不必显式的写出模板参数了,C++编译器可以自动帮我们完成类型推断,就像下面这样:

struct User { std::string name{}; }; template struct Book { T auther; }; template auto create_book(T user) { return Book{user}; } int main() { // 自动根据构造函数参数推断类型模板参数 Book book_1{User{}}; // 自动根据函数参数推断函数模板参数 auto book_2 = create_book(User{}); }

但是,值得注意的是,上面两种情况中,类型模板参数和函数模板参数的类型自动推断逻辑实际上存在着细微区别:与函数模板参数会自动推断类型的左右值不同,类型模板参数推断是不会自动推断类型模板参数的左右值的,而只会将模板参数自动推断为类型本身,我们通过下面的例子来说明这个问题:

struct User { std::string name{}; }; template struct Book { explicit Book(T &&_x) : x(std::forward(_x)) {} T x; }; template auto create_book(T &&user) { return Book{std::forward(user)}; } int main() { // 类型模板仅会推断为类型本身,不会推断为类型的左值或右值 Book book{User()}; // book.x的类型只会被自动推断为 User, 而不会被自动推断为 User&& 或 User& // 此时 book.x 的类型为 User auto x_1 = book.x; // 除非你显式将类模板类型声明为引用类型 Book book_2{User{}}; // 此时 book.x 的类型为 const User & auto x_2 = book_2.x; User user; // 自动推导Book的模板参数类型为 User, // Book 仅有一个接受 User&& 构造函数,无法接受一个左值作为参数 Book book_3{user}; // 因此这个写法是错的 // 但可以接受右值 Book book_4{std::move(user)}; // 但是函数模板参数是会自动推导参数的左右值的 auto book_5 = create_book(User{}); // OK auto book_6 = create_book(user); // OK return 0; }

为什么C++语法要这样设计呢?为什么设计语法时不让类型模板参数推断的行为与函数模板参数的推断行为保持一致呢?

其实我们考虑一下类型模板参数自动推断的使用场景就可以想到这样设计的理由了,考虑一下下面的例子:

int main() { std::vector num_vec{1, 2, 3, 4, 5}; }

在这个例子中,我们当然是希望 num_vec的类型被推断为std::vector 而不是 std::vector ,但我们直接写出的构造函数的值都是右值,类型是 int&& ,如果类型模板参数推断也包含对左右值的推断,那么上面这样的示例的结果就不是我们的所期望的结果了。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有